package org.breathe.protocal;

import io.netty.buffer.ByteBuf;
import org.breathe.protocal.decode.*;

/**
 * @author: breathe
 * @createTime: 2025-05-12
 */
public abstract class Resp {
    public static final byte[] CRLF = "\r\n".getBytes();

    /**
     *
     * SimpleString  +OK\r\n
     * Errors  -Error message\r\n
     * RedisInteger  :0\r\n
     * BulkString  $6\r\nfoobar\r\n
     * RespArray  *2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n
     */
    public static Resp decode(ByteBuf buffer) {
        if (buffer.readableBytes() <= 0) {
            throw new RuntimeException("Don't have complete command.");
        }
        char c = (char)buffer.readByte();
        switch (c) {
            case '+':
                return new SimpleString(getString(buffer));
            case '-':
                return new Errors(getString(buffer));
            case ':':
                return new RespInteger(getNumber(buffer));
            case '$':
                int length = getNumber(buffer);
                if (buffer.readableBytes() < length + 2) {
                    throw new IllegalArgumentException("Don't have \\r\\n");
                }
                byte[] content;
                if (length == -1) {
                    content = null;
                } else {
                    content = new byte[length];
                    buffer.readBytes(content);
                }
                if (buffer.readByte() != '\r' || buffer.readByte() != '\n') {
                    throw new IllegalArgumentException("Don't have \\r\\n");
                }
                return new BulkString(content);
            case '*':
                int number = getNumber(buffer);
                Resp[] array = new Resp[number];
                for (int i = 0; i < number; i ++) {
                    array[i] = decode(buffer);
                }
                return new RespArray(array);
            default:
                throw new IllegalArgumentException("not match Resp type");
        }
    }
    public abstract void encode(Resp resp, ByteBuf buffer);
    private static String getString(ByteBuf buffer) {
        char c;
        StringBuilder result = new StringBuilder();
        while ((c = (char)buffer.readByte()) != '\r' && buffer.readableBytes() > 0) {
            result.append(c);
        }
        if (buffer.readableBytes() <= 0 || buffer.readByte() != '\n') {
            throw new IllegalArgumentException("Don't have \\r\\n");
        }
        return result.toString();
    }
    private static int getNumber(ByteBuf buffer) {
        char c;
        c = (char)buffer.readByte();
        boolean positive = true;
        int value = 0;
        if (c == '-') {
            positive = false;
        } else {
            value = c - '0';
        }
        while((c = (char)buffer.readByte()) != '\r' && buffer.readableBytes() > 0){
            value = value * 10 + (c - '0');
        }
        if (buffer.readableBytes() <= 0 || buffer.readByte() != '\n') {
            throw new IllegalArgumentException("Don't have \\r\\n");
        }
        if (!positive) {
            value *= -1;
        }
        return value;
    }
}
